package SC12Project.pm2.publish;

import java.rmi.RemoteException;
import java.util.List;

import org.apache.juddi.v3.client.ClassUtil;
import org.apache.juddi.v3.client.config.UDDIClientContainer;
import org.apache.juddi.v3.client.transport.Transport;
import org.apache.juddi.v3.client.transport.TransportException;
import org.apache.juddi.v3_service.JUDDIApiPortType;
import org.apache.log4j.Logger;
import org.uddi.api_v3.AccessPoint;
import org.uddi.api_v3.AuthToken;
import org.uddi.api_v3.BindingDetail;
import org.uddi.api_v3.BindingTemplate;
import org.uddi.api_v3.BindingTemplates;
import org.uddi.api_v3.BusinessDetail;
import org.uddi.api_v3.BusinessEntity;
import org.uddi.api_v3.BusinessInfo;
import org.uddi.api_v3.BusinessList;
import org.uddi.api_v3.BusinessService;
import org.uddi.api_v3.BusinessServices;
import org.uddi.api_v3.CategoryBag;
import org.uddi.api_v3.DeleteBusiness;
import org.uddi.api_v3.Description;
import org.uddi.api_v3.FindBusiness;
import org.uddi.api_v3.FindQualifiers;
import org.uddi.api_v3.FindService;
import org.uddi.api_v3.GetAuthToken;
import org.uddi.api_v3.IdentifierBag;
import org.uddi.api_v3.InstanceDetails;
import org.uddi.api_v3.KeyedReference;
import org.uddi.api_v3.Name;
import org.uddi.api_v3.OverviewDoc;
import org.uddi.api_v3.OverviewURL;
import org.uddi.api_v3.SaveBinding;
import org.uddi.api_v3.SaveBusiness;
import org.uddi.api_v3.SaveService;
import org.uddi.api_v3.SaveTModel;
import org.uddi.api_v3.ServiceDetail;
import org.uddi.api_v3.ServiceInfo;
import org.uddi.api_v3.ServiceList;
import org.uddi.api_v3.TModel;
import org.uddi.api_v3.TModelDetail;
import org.uddi.api_v3.TModelInstanceDetails;
import org.uddi.api_v3.TModelInstanceInfo;
import org.uddi.v3_service.DispositionReportFaultMessage;
import org.uddi.v3_service.UDDIInquiryPortType;
import org.uddi.v3_service.UDDIPublicationPortType;
import org.uddi.v3_service.UDDISecurityPortType;

import SC12Project.pm2.Strings.GlobalStrings;

public class JuddiClient
{

    private static UDDISecurityPortType security = null; // This variable is used to login in the JUDDI server

    private static JUDDIApiPortType juddiApi = null; // This variable is used to access all the API methods

    private static UDDIPublicationPortType publish = null; // This variable is used to publish (register) a service to
                                                           // the JUDDI server

    private static AuthToken myAuthToken = null; // This variable is used to cache user authToken,

    private static Logger logger = Logger.getLogger( JuddiClient.class );

    public UDDIInquiryPortType getInquiry()
    {
        return inquiry;
    }

    private static UDDIInquiryPortType inquiry = null;

    public void initilize()
    {
        try
        {
            String clazz =
                UDDIClientContainer.getUDDIClerkManager( null ).getClientConfig().getUDDINode( "default" ).getProxyTransport();
            Class<?> transportClass = ClassUtil.forName( clazz, Transport.class );
            if ( transportClass != null )
            {
                Transport transport = (Transport) transportClass.getConstructor( String.class ).newInstance( "default" );
                security = transport.getUDDISecurityService();
                juddiApi = transport.getJUDDIApiService();
                publish = transport.getUDDIPublishService();
                inquiry = transport.getUDDIInquiryService();
            }
        }
        catch ( Exception e )
        {
            e.printStackTrace();
        }
    }

    public void serverLogin( String userName, String password )
        throws DispositionReportFaultMessage, RemoteException
    {
        GetAuthToken getAuthTokenMyPub = new GetAuthToken();
        getAuthTokenMyPub.setUserID( userName );
        getAuthTokenMyPub.setCred( password );
        // Making API call that retrieves the authentication token for the user
        // You can use the group name and password assigned to you to access the JUDDIv3 server for this course.
        myAuthToken = security.getAuthToken( getAuthTokenMyPub );
        logger.info( " User AUTHTOKEN = " + myAuthToken.getAuthInfo() );
    }

    public void deleteBusiness( String businessName )
        throws TransportException, DispositionReportFaultMessage, RemoteException
    {

        Name name = new Name();
        name.setValue( businessName );
        FindBusiness fb = new FindBusiness();
        fb.setAuthInfo( myAuthToken.getAuthInfo() );
        fb.getName().add( name );

        BusinessList foundBusinesses = inquiry.findBusiness( fb );

        if ( foundBusinesses.getBusinessInfos() != null )
        {
            for ( BusinessInfo business : foundBusinesses.getBusinessInfos().getBusinessInfo() )
            {
                logger.info( "delete business: " + business.getName() + " - " + business.getBusinessKey() );
                DeleteBusiness db = new org.uddi.api_v3.DeleteBusiness();
                db.setAuthInfo( myAuthToken.getAuthInfo() );
                db.getBusinessKey().add( business.getBusinessKey() );
                publish.deleteBusiness( db );
            }
        }
        else
        {
            logger.info( "didn't found any business " + name.getValue() );
        }
    }

    public void publishService( String serviceName, String serviceDescription, String url )
    {
        try
        {
            String myBusinessKey = null;
            String myTempServKey = null;

            BusinessEntity myBusEntity = new BusinessEntity();
            Name myBusName = new Name();
            myBusName.setValue( GlobalStrings.GROUP_NAME );
            Description myBusEntDescription = new Description();
            myBusEntDescription.setValue( "Our intercultural group" );
            myBusEntity.getName().add( myBusName );
            myBusEntity.getDescription().add( myBusEntDescription );

            myBusinessKey = checkBusinessEntity( GlobalStrings.GROUP_NAME );
            if ( myBusinessKey.equals( "" ) )
            {
                SaveBusiness sb = new SaveBusiness();
                sb.getBusinessEntity().add( myBusEntity );
                // sb.setAuthInfo(myPubAuthToken.getAuthInfo());
                sb.setAuthInfo( myAuthToken.getAuthInfo() );
                BusinessDetail bd = publish.saveBusiness( sb );
                myBusinessKey = bd.getBusinessEntity().get( 0 ).getBusinessKey();
                System.out.println( "myBusinessKey is " + myBusinessKey );
            }
            // Adding the business entity to the "save" structure, using our publisher's authentication info and saving
            // away.
            logger.info( "myBusiness key:  " + myBusinessKey );

            // Creating a service to save. Only adding the minimum data: the parent business key retrieved from saving
            // the business
            // above and a single name.
            BusinessService myService = new BusinessService();
            myService.setBusinessKey( myBusinessKey );

            Name myServName = new Name();
            myServName.setValue( serviceName );
            myService.getName().add( myServName );

            Description d = new Description();
            d.setValue( serviceDescription );
            myService.getDescription().add( d );

            BusinessServices businessServices = new BusinessServices();
            List<BusinessService> bslist = businessServices.getBusinessService();
            bslist.add( myService );
            myBusEntity.setBusinessServices( businessServices );

            // Adding the service to the "save" structure, using our publisher's authentication info and saving away.
            myTempServKey = checkBusinessService( serviceName );
            SaveService ss = new SaveService();
            if ( !myTempServKey.equals( "" ) )
            {
                myService.setServiceKey( myTempServKey );
            }
            ss.getBusinessService().add( myService );
            ss.setAuthInfo( myAuthToken.getAuthInfo() );
            ServiceDetail sd = publish.saveService( ss );
            String myServKey = sd.getBusinessService().get( 0 ).getServiceKey();
            logger.info( "myService key:  " + myServKey );

            // Add binding templates
            BindingTemplates templates = new BindingTemplates();
            myService.setBindingTemplates( templates );

            BindingTemplate myTemplate = new BindingTemplate();
            myTemplate.setServiceKey( myServKey );

            List<BindingTemplate> templateList = templates.getBindingTemplate();
            templateList.add( myTemplate );

            // Add TModel
            /**
             * This creates the unique, well-defined tModel representing the service's WSDL
             */
            // String url = "http://vmjacobsen4.informatik.tu-muenchen.de:8080/axis2/services/HelloworldWSDL2?wsdl2";
            // String url = "http://localhost:8080/axis2/services/WeatherProvider?wsdl";
            TModelDetail tModelDetail = publishWSDL_tModel( serviceName, url, myAuthToken.getAuthInfo() );
            List<TModel> tModelList = tModelDetail.getTModel();

            TModelInstanceDetails tModelInstanceDetails = new TModelInstanceDetails();
            List<TModelInstanceInfo> tModelInstanceInfoList = tModelInstanceDetails.getTModelInstanceInfo();

            for ( TModel tm : tModelList )
            {
                TModelInstanceInfo tModelInstanceInfo = new TModelInstanceInfo();
                tModelInstanceInfoList.add( tModelInstanceInfo );
                tModelInstanceInfo.setTModelKey( tm.getTModelKey() );
                InstanceDetails instanceDetails = new InstanceDetails();
                instanceDetails.setInstanceParms( serviceName + "tModel instance" );
                tModelInstanceInfo.setInstanceDetails( instanceDetails );
            }

            /**
             * Associate the set of tModels with the Service's BindingTemplate
             */
            myTemplate.setTModelInstanceDetails( tModelInstanceDetails );

            /**
             * The binding template needs an [ accessPoint | hostRedirector ]
             */
            AccessPoint weatherServiceAccessPoint = createAccessPoint( url.substring( 0, url.lastIndexOf( "?" ) ) );
            myTemplate.setAccessPoint( weatherServiceAccessPoint );

            // set CategoryBag
            myTemplate.setCategoryBag( tModelList.get( 0 ).getCategoryBag() );

            // Adding the binding to the "save" structure, using our publisher's authentication info and saving away.
            SaveBinding sbinding = new SaveBinding();
            sbinding.getBindingTemplate().add( myTemplate );
            sbinding.setAuthInfo( myAuthToken.getAuthInfo() );
            BindingDetail binddetail = publish.saveBinding( sbinding );
            logger.info( "My binding key:  " + binddetail.getBindingTemplate().get( 0 ).getBindingKey() );

            // update the service to the "save" structure, using our publisher's authentication info and saving away.
            SaveService updates = new SaveService();
            myService.setServiceKey( myServKey );
            updates.getBusinessService().add( myService );
            updates.setAuthInfo( myAuthToken.getAuthInfo() );
            sd = publish.saveService( updates );
            myServKey = sd.getBusinessService().get( 0 ).getServiceKey();
            logger.info( "myService key:  " + myServKey );

        }
        catch ( Exception e )
        {
            e.printStackTrace();
        }
    }

    private String checkBusinessEntity( String entityName )
        throws TransportException, DispositionReportFaultMessage, RemoteException
    {
        Name name = new Name();
        name.setValue( entityName );
        FindBusiness fb = new FindBusiness();
        fb.setAuthInfo( myAuthToken.getAuthInfo() );
        fb.getName().add( name );

        BusinessList foundBusinesses = inquiry.findBusiness( fb );

        if ( foundBusinesses.getBusinessInfos() != null )
        {
            BusinessInfo business = new BusinessInfo();
            business = foundBusinesses.getBusinessInfos().getBusinessInfo().get( 0 );
            return business.getBusinessKey();
        }
        else
        {
            return "";
        }
    }

    private String checkBusinessService( String serviceName )
        throws TransportException, DispositionReportFaultMessage, RemoteException
    {
        Name name = new Name();
        name.setValue( serviceName );
        FindService fs = new FindService();
        fs.setAuthInfo( myAuthToken.getAuthInfo() );
        fs.getName().add( name );

        ServiceList foundServices = inquiry.findService( fs );

        if ( foundServices.getServiceInfos() != null )
        {
            ServiceInfo service = new ServiceInfo();
            service = foundServices.getServiceInfos().getServiceInfo().get( 0 );
            return service.getServiceKey();
        }
        else
        {
            return "";
        }
    }

    /**
     * Creates a tModel, identifying WSDL endpoint. This is the best practices model for registering a WSDL describing a
     * business service. Applications searching registries for WSDL will be searching registries for this data
     * structure. The data structure contains an endpoint for the Service's WSDL document, so each service will need a
     * unique tModel. Best Practices are outlined in the document
     * http://www.oasis-open.org/committees/uddi-spec/doc/bp/uddi-spec-tc-bp-using-wsdl-v108-20021110.htm
     */
    private TModelDetail publishWSDL_tModel( String serviceName, String url, String authinfo )
        throws Exception
    {

        TModel tModel = new TModel();

        // set the name of tModel
        Name tModelName = new Name();
        tModelName.setLang( "en" );
        tModelName.setValue( serviceName + "WSDLTModel SC2012" );
        tModel.setName( tModelName );

        tModel.setDeleted( false );

        // set Overview Docs
        OverviewDoc overviewDoc = new OverviewDoc();
        OverviewURL overviewurl = new OverviewURL();
        overviewurl.setUseType( "WSDL source document" );
        overviewurl.setValue( url );
        overviewDoc.setOverviewURL( overviewurl );
        List<OverviewDoc> overviewdoclist = tModel.getOverviewDoc();
        overviewdoclist.add( overviewDoc );

        TModelDetail tModelDetail = new TModelDetail();
        List<TModel> tModelList = tModelDetail.getTModel();
        tModelList.add( tModel );

        // Adding the tModel to the "save" structure, using our publisher's authentication info and saving away.
        SaveTModel saveTModel = new SaveTModel();
        saveTModel.getTModel().addAll( tModelList );
        saveTModel.setAuthInfo( authinfo );
        tModelDetail = publish.saveTModel( saveTModel );

        String tModelKey = tModelDetail.getTModel().get( 0 ).getTModelKey();
        logger.info( "tModel key: " + tModelKey );
        tModel.setTModelKey( tModelKey );

        // set CategoryBag
        CategoryBag catBag = new CategoryBag();
        List<KeyedReference> krlist = catBag.getKeyedReference();
        KeyedReference kr = new KeyedReference();
        kr.setKeyName( "uuid-org:types" );
        kr.setKeyValue( "wsdlSpec" );
        kr.setTModelKey( tModelKey );
        krlist.add( kr );

        tModel.setCategoryBag( catBag );

        // set the IdentifierBag
        IdentifierBag idBag = new IdentifierBag();
        List<KeyedReference> idkeylist = idBag.getKeyedReference();
        KeyedReference idKey = new KeyedReference();
        idKey.setKeyName( "service name" );
        idKey.setKeyValue( serviceName );
        idKey.setTModelKey( tModelKey );
        idkeylist.add( idKey );

        tModel.setIdentifierBag( idBag );

        // udpate the tModel to the "save" structure, using our publisher's authentication info and saving away.
        SaveTModel updateTModel = new SaveTModel();
        updateTModel.getTModel().addAll( tModelList );
        updateTModel.setAuthInfo( authinfo );
        tModelDetail = publish.saveTModel( updateTModel );

        tModelKey = tModelDetail.getTModel().get( 0 ).getTModelKey();
        logger.info( "tModel key: " + tModelKey );

        return tModelDetail;
    }

    // public BusinessList findBusiness(String searchPattern) throws Exception
    // {
    // Name name = new Name();
    // name.setValue(searchPattern);
    // FindQualifiers qualifiers = new FindQualifiers();
    // qualifiers.getFindQualifier().add(org.apache.juddi.query.util.FindQualifiers.APPROXIMATE_MATCH);
    // FindBusiness findBusiness = new FindBusiness();
    // findBusiness.getName().add(name);
    // findBusiness.setFindQualifiers(qualifiers);
    // return inquiry.findBusiness(findBusiness);
    // }

    public ServiceList findServices( String searchPattern )
        throws DispositionReportFaultMessage, RemoteException
    {
        Name name = new Name();
        name.setValue( searchPattern );
        FindQualifiers qualifiers = new FindQualifiers();
        qualifiers.getFindQualifier().add( org.apache.juddi.query.util.FindQualifiers.APPROXIMATE_MATCH );
        FindService findService = new FindService();
        findService.getName().add( name );
        findService.setFindQualifiers( qualifiers );
        return inquiry.findService( findService );
    }

    private AccessPoint createAccessPoint( String url )
    {
        AccessPoint accessPoint = new AccessPoint();
        accessPoint.setUseType( "http" );
        accessPoint.setValue( url );
        return accessPoint;
    }

}
